Assembly Language
©
Copyright Brian Brown, 1988-2000. All rights reserved.
| Notes | Home Page |
ASSEMBLY LANGUAGE PROGRAMMING, Part 6
PARAMETER PASSING
Parameter passing refers to the exchange of data
between modules. There are many ways this information can be exchanged.
Consider the following simple program which adds two numbers together, storing the result. All data has been declared as common.
TITLE CommonData .MODEL Large .STACK 200h .DATA num1 dw 22 num2 dw 32 result dw 0 .CODE addnum proc far mov ax, [num1] mov bx, [num2] add ax, bx mov [result], ax ret addnum endp start: mov ax, @data mov ds, ax call addnum ; add num1 and num2 mov ax, 4c00h int 21h END start
Routines must ensure that they do not corrupt any registers other than those which have been specified. The programmer first determines which registers will be used and which can be altered (contents destroyed).
Consider the following implementation of the previous addition program to use register variables.
TITLE CommonData .MODEL Large .STACK 200h .DATA num1 dw 22 num2 dw 32 result dw 0 .CODE addnum proc far ; accepts num1 in ax, num2 in bx, returns result in dx push ax add ax, bx mov dx, ax pop ax ret addnum endp start: mov ax, @data mov ds, ax mov ax, [num1] mov bx, [num2] call addnum ; add num1 and num2 mov [result], dx mov ax, 4c00h int 21h END start
The advantage is that only the calling module alters the data, whilst the module addnum only works on copies of the data. In this way, it is easier to track which modules affect the data variables.
The module then accesses the parameters on the stack using the appropriate addressing mode.
Upon return to the calling module, the stack space is deallocated using appropriate pop or stack pointer adjustment instructions.
There are two ways in which data may be referenced using the stack.
Call by value is normally used for simple data types, whilst call by reference is used for data types like arrays and records, because of the amount of memory space they occupy (and stack space is normally limited).
Consider the following program for an MC6802 processor which uses Call by Value to add two variables together.
CPU 6802 HOF MOT ORG 100H Num1: DFB 10 Num2: DFB 20 Result: DFB 0 Start: PSHA ; Make room for result on stack LDAA Num1 LDAB Num2 PSHA ; Place copy Num1 on stack PSHB ; Place copy of Num2 on stack JSR Addup PULB ; remove copy of Num2 PULA ; remove copy of Num1 PULA ; get result from Addup STAA Result Exit: BRA Exit Addup: TSX ; transfer SP into IX register PSHA ; save registers PSHB LDAA 02,X ; Get Num2 LDAB 03,X ; Get Num1 ABA ; Add Num1 and Num2 STAA 04,X ; Store on stack for return PULB ; Recover original register values PULA RTS END Start
PARAMETER PASSING FOR THE 8088 PROCESSOR
ACCESSING THE STACK FRAME INSIDE A MODULE
Lets look at how a module
handles the stack frame. Because each module will use the BP register to access
any parameters, its first chore is to save the contents of BP.
push bp
It then transfers the address of SP into BP; BP now points to the top of the stack.
mov bp,sp
thus the first two instructions in a module will be the combination,
push bp mov bp,sp
ALLOCATION OF LOCAL STORAGE INSIDE A MODULE
Local variables are
allocated on the stack using a
sub sp, n
instruction. This decrements the stack pointer by the number of bytes specified by n. For example, a module might want to use temporary storage space for an integer i, which equates to the machine code instruction
sub sp, 2
Pictorially, the stack frame looks like,
+---------+ | ihigh |<-- SP +---------+ | ilow | +---------+ | BPhigh |<-- BP +---------+ | BPlow | +---------+
The local variable i can be accessed using SS:BP - 2, so the statement,
i = 24;
is equivalent to
mov [bp - 2], 18
Note that twenty-four decimal is eighteen hexadecimal.
DEALLOCATION OF LOCAL VARIABLES WHEN THE MODULE TERMINATES
When the
module terminates, it must deallocate the space it allocated for the variable
i on the stack. Referring to the above diagram, it can be seen that BP
still holds the top of the stack as it was when the module was first entered. BP
has been used for two purposes,
The deallocation of any local variables (in our case the variable i) will occur with the following code sequence,
mov sp, bp ;this recovers SP, deallocating i pop bp ;SP now is the same as on entry to module
THE PASSING OF PARAMETERS TO A MODULE
Consider the following module
call in a high level langauge.
add_two( 10, 20 );
The language pushes parameters (the values 10 and 20) right to left, thus the sequence of statements which implement this are,
push ax ; assume ax contains 2nd parameter, ie, integer ; value 20 push cx ; assume cx contains 1st parameter, ie, integer ; value 10 call add_two
The stack frame now looks like,
+---------+ | Return |<-- SP +---------+ | address | +---------+ | 00 | ;1st parameter, integer value 10 +---------+ | 0A | +---------+ | 00 | ;2nd parameter, integer value 20 +---------+ | 14 | +---------+
Remembering that the first two statements of module add_two() are,
add_two: push bp mov bp, sp
The stack frame now looks like (after those first two instructions inside add_two)
+---------+ | BPhigh |<-- BP <-- SP +---------+ | BPlow | +---------+ | Return | +---------+ | address | +---------+ | 0A | ;1st parameter, integer value 10 +---------+ | 00 | +---------+ | 14 | ;2nd parameter, integer value 20 +---------+ | 00 | +---------+
ACCESSING OF PASSED PARAMETERS WITHIN THE CALLED MODULE
It should
be clear that the passed parameters to module add_two() are accessed relative to
BP, with the 1st parameter residing at [BP+4], and the 2nd parameter residing at
[BP+6].
DEALLOCATION OF PASSED PARAMETERS
The two parameters passed in the
call to module add_two() were pushed onto the stack frame before the module was
called. Upon return from the module, they are still on the stack frame, so now
they must be deallocated. The instruction which does this is,
add sp, 4
where SP is adjusted upwards four bytes (ie, past the two integers).